package org.sanguine.study.hometasks.second;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class Task7 {
	public static class Monomial {
		private double coefficient;
		private int degree;
		
		public Monomial(int degree, double coefficient) {
			if (degree >= 0) {
				this.degree = degree;
				this.coefficient = coefficient;
			} else throw new IllegalArgumentException("Degree of monomial must be positive");
		}
		
		public PolynomialOnLists multify(PolynomialOnLists polynomial) {
			if (polynomial == null) return null;
			
			List<Double> newCoefficients = new LinkedList<>();
			newCoefficients.addAll(Collections.nCopies(degree, new Double(0.0)));
			
			for (Double value : polynomial.getCoefficients()) newCoefficients.add(value * coefficient);
			Collections.reverse(newCoefficients);
			return new PolynomialOnLists(newCoefficients.toArray(new Double[newCoefficients.size()]));
		}
	}
	
	public static class PolynomialOnLists {
		private List<Double> coefficients;
		
		/**
		 * Create new Polynomial with presented coefficients by order from highest to lowest
		 * @param coefficients
		 * @throws IllegalArgumentException if coefficients aren't present
		 */
		
		public PolynomialOnLists(Double ... coeffs) {
			if (coeffs != null && coeffs.length > 0) {
				coefficients = new ArrayList<>(coeffs.length);
				for (int i = coeffs.length - 1; i >= 0; i--) coefficients.add(coeffs[i]);
			} else throw new IllegalArgumentException("Coefficients must be set");
		}
		
		/**
		 * Return degree of polynomial
		 * @return degree of polynomial from zero
		 */
		
		public int getDegree() {
			return coefficients.size() - 1;
		}
		
		public Double getCoefficient(int rank) {
			return (rank < 0 || rank > getDegree()) ? null : coefficients.get(rank);
		}
		
		/**
		 * Get coefficients of polynomial from lowest to highest
		 * @return List of coefficients (unmodifiable)
		 */
		
		public List<Double> getCoefficients() {
			return Collections.unmodifiableList(coefficients);
		}
		
		public PolynomialOnLists add(PolynomialOnLists another) {
			if (another == null) return this;
			
			Double[] newCoeffs;
			int degree = coefficients.size() - 1;
			int anotherDegree = another.coefficients.size() - 1;
			
			if (degree >= anotherDegree) {
				newCoeffs = new Double[degree + 1];
				int i = degree;
				while (i > anotherDegree) {
					newCoeffs[degree - i] = coefficients.get(i);
					i--;
				}
				while (i >= 0) {
					newCoeffs[degree - i] = coefficients.get(i) + another.coefficients.get(i);
					i--;
				}
			} else {
				newCoeffs = new Double[anotherDegree + 1];
				int i = anotherDegree;
				while (i > degree) {
					newCoeffs[anotherDegree - i] = another.coefficients.get(i);
					i--;
				}
				while (i >= 0) {
					newCoeffs[anotherDegree - i] = coefficients.get(i) + another.coefficients.get(i);
					i--;
				}
			}
			
			return new PolynomialOnLists(newCoeffs);
		}
		
		public PolynomialOnLists multify(PolynomialOnLists another) {
			if (another == null) return null;
			
			Monomial monomial = new Monomial(0, another.getCoefficient(0));
			PolynomialOnLists resultPolynomial = monomial.multify(this);
			
			for (int i = 1; i <= another.getDegree(); i++) {
				monomial = new Monomial(i, another.getCoefficient(i));
				PolynomialOnLists tmpResult = monomial.multify(this);
				resultPolynomial = resultPolynomial.add(tmpResult);
			}
			return resultPolynomial;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result
					+ ((coefficients == null) ? 0 : coefficients.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (!(obj instanceof PolynomialOnLists))
				return false;
			PolynomialOnLists other = (PolynomialOnLists) obj;
			if (coefficients == null) {
				if (other.coefficients != null)
					return false;
			} else if (!coefficients.equals(other.coefficients))
				return false;
			return true;
		}
		
		
	}

}
